/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "myassert.h"

#include "MudCreature.h"
#include "CmdVisitor.h"
#include "MudPlayer.h"
#include "Room.h"
#include "Utils.h"
#include "config.h"
#include "Utils.h"

using namespace Chronos;
using namespace std;


MudCreature::MudCreature(const string& name_, const string& descr_, int maxHealth_, int speed_, int maxDamage_, int hitChance_, bool aggro_)
    : MudMobile(name_, descr_, maxHealth_, speed_, maxDamage_, hitChance_)
    , aggressive(aggro_)
    , minChatInterval(seconds(4))
    , maxChatInterval(seconds(12))
{}


MudCreature::MudCreature(const MudCreature& rhs)
    : MudMobile(rhs)
    , aggressive(rhs.aggressive)
    , messages(rhs.messages)
    , minChatInterval(rhs.minChatInterval)
    , maxChatInterval(rhs.maxChatInterval)
{}


VISITOR_ACCEPT(MudCreature)


bool MudCreature::handleRoomEvent(MudMobile& mobile, RoomEvent event) {
    ASSERT_NOT_EQUAL((int)this, (int)&mobile);
	switch (event) {
	case MUDMOBILE_ARRIVE:
	    if (aggressive) addTarget(mobile);
		break;
	default:
		break;		
	}
    return true;
}


void MudCreature::handleTrigger(MudTriggerAction action, MudMobile* cause, const std::string& msg) {
	switch (action) {
	case MESSAGE:
		cause->write(msg);
		break;
	case ATTACK:
		cause->write(msg);
		addTarget(*cause);
		break;
	}
}


unsigned int MudCreature::doEmote() {
    if (messages.isEmpty()) return 0;
    unsigned int delay = Utils::roll(minChatInterval, maxChatInterval);
    if (!inCombat) room->showText(messages.getMessage());
    return delay;
}


void MudCreature::setChatInterval(unsigned int min, unsigned int max) {
    minChatInterval = min;
    maxChatInterval = max;
}


void MudCreature::addChat(const string& msg, unsigned int weight) {
    messages.addMessage(msg, weight);
}


unsigned int MudCreature::doCombat() {
    if (!inCombat) return 0;

    if (this->room != combatTarget->getRoom()) {
        room->showText(name + " looks around for a target.");
        return stats[Stats::speed];
    }

    if (Utils::roll(1,100) <= stats[Stats::hitChance]) {
        int dmg = Utils::roll(1, stats[Stats::maxDamage]);
        room->showText(name + " hits " + combatTarget->getName() + " for " + Utils::itoa(dmg) + ".", *combatTarget);
        if (!combatTarget->takeDmg(*this, dmg)) {
			return 0;
		}
    } else {
        combatTarget->miss(*this);
        room->showText(name + " misses " + combatTarget->getName() + ".", *combatTarget);
    }
    return stats[Stats::speed];
}


void MudCreature::miss(MudMobile& source) {
    addTarget(source);
}


bool MudCreature::takeDmg(MudMobile& source, unsigned int dmg) {
    addTarget(source);
    stats.modifyHealth(-dmg);
    if (stats.getHealth() <= 0) {
		string cause = "killed by "+ source.getName();
		room->showText(name + " is " + cause + ".", source);
        die(cause);
        room->removeObject(this);
        delete this;
		return false;
    }
	return true;
}


bool MudCreature::isAggro() const { return aggressive; }

